//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.zz.gmhelper;

import org.bouncycastle.crypto.*;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.DSAEncoding;
import org.bouncycastle.crypto.signers.DSAKCalculator;
import org.bouncycastle.crypto.signers.RandomDSAKCalculator;
import org.bouncycastle.crypto.signers.StandardDSAEncoding;
import org.bouncycastle.math.ec.*;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;

public class SM2Signer implements Signer, ECConstants {
  private final DSAKCalculator kCalculator;
  private final Digest digest;
  private final DSAEncoding encoding;
  private ECDomainParameters ecParams;
  private ECPoint pubPoint;
  private ECKeyParameters ecKey;
  private byte[] z;

  public SM2Signer() {
    this(StandardDSAEncoding.INSTANCE, new SM3Digest());
  }

  public SM2Signer(Digest var1) {
    this(StandardDSAEncoding.INSTANCE, var1);
  }

  public SM2Signer(DSAEncoding var1) {
    this.kCalculator = new RandomDSAKCalculator();
    this.encoding = var1;
    this.digest = new SM3Digest();
  }

  public SM2Signer(DSAEncoding var1, Digest var2) {
    this.kCalculator = new RandomDSAKCalculator();
    this.encoding = var1;
    this.digest = var2;
  }

  public void init(boolean var1, CipherParameters var2) {
    CipherParameters var3;
    byte[] var4;
    if (var2 instanceof ParametersWithID) {
      var3 = ((ParametersWithID) var2).getParameters();
      var4 = ((ParametersWithID) var2).getID();
      if (var4.length >= 8192) {
        throw new IllegalArgumentException("SM2 user ID must be less than 2^16 bits long");
      }
    } else {
      var3 = var2;
      var4 = Hex.decodeStrict("31323334353637383132333435363738");
    }

    if (var1) {
      if (var3 instanceof ParametersWithRandom) {
        ParametersWithRandom var5 = (ParametersWithRandom) var3;
        this.ecKey = (ECKeyParameters) var5.getParameters();
        this.ecParams = this.ecKey.getParameters();
        this.kCalculator.init(this.ecParams.getN(), var5.getRandom());
      } else {
        this.ecKey = (ECKeyParameters) var3;
        this.ecParams = this.ecKey.getParameters();
        this.kCalculator.init(this.ecParams.getN(), CryptoServicesRegistrar.getSecureRandom());
      }

      this.pubPoint =
          this.createBasePointMultiplier()
              .multiply(this.ecParams.getG(), ((ECPrivateKeyParameters) this.ecKey).getD())
              .normalize();
    } else {
      this.ecKey = (ECKeyParameters) var3;
      this.ecParams = this.ecKey.getParameters();
      this.pubPoint = ((ECPublicKeyParameters) this.ecKey).getQ();
    }

    this.z = this.getZ(var4);
    this.digest.update(this.z, 0, this.z.length);
  }

  public void update(byte var1) {
    this.digest.update(var1);
  }

  public void update(byte[] var1, int var2, int var3) {
    this.digest.update(var1, var2, var3);
  }

  public boolean verifySignature(byte[] var1) {
    try {
      BigInteger[] var2 = this.encoding.decode(this.ecParams.getN(), var1);
      return this.verifySignature(var2[0], var2[1]);
    } catch (Exception var3) {
      return false;
    }
  }

  public void reset() {
    this.digest.reset();
    if (this.z != null) {
      this.digest.update(this.z, 0, this.z.length);
    }
  }

  public byte[] generateSignature() throws CryptoException {
    byte[] var1 = this.digestDoFinal();
    BigInteger n = this.ecParams.getN();
    BigInteger var3 = this.calculateE(n , var1);
    BigInteger var4 = ((ECPrivateKeyParameters) this.ecKey).getD();
    ECMultiplier var7 = this.createBasePointMultiplier();

    while (true) {
      BigInteger var5;
      BigInteger k;
      do {
        k = this.kCalculator.nextK();
        ECPoint var9 = var7.multiply(this.ecParams.getG(), k).normalize();
        var5 = var3.add(var9.getAffineXCoord().toBigInteger()).mod(n);
      } while (var5.equals(ZERO));

      if (!var5.add(k).equals(n )) {
        BigInteger var11 = BigIntegers.modOddInverse(n, var4.add(ONE));
        BigInteger var6 = k.subtract(var5.multiply(var4)).mod(n);
        var6 = var11.multiply(var6).mod(n);
        if (!var6.equals(ZERO)) {
          try {
            return this.encoding.encode(this.ecParams.getN(), var5, var6);
          } catch (Exception var10) {
            throw new CryptoException("unable to encode signature: " + var10.getMessage(), var10);
          }
        }
      }
    }
  }

  private boolean verifySignature(BigInteger var1, BigInteger var2) {
    BigInteger var3 = this.ecParams.getN();
    if (var1.compareTo(ONE) >= 0 && var1.compareTo(var3) < 0) {
      if (var2.compareTo(ONE) >= 0 && var2.compareTo(var3) < 0) {
        byte[] var4 = this.digestDoFinal();
        BigInteger var5 = this.calculateE(var3, var4);
        BigInteger var6 = var1.add(var2).mod(var3);
        if (var6.equals(ZERO)) {
          return false;
        } else {
          ECPoint var7 = ((ECPublicKeyParameters) this.ecKey).getQ();
          ECPoint var8 =
              ECAlgorithms.sumOfTwoMultiplies(this.ecParams.getG(), var2, var7, var6).normalize();
          if (var8.isInfinity()) {
            return false;
          } else {
            BigInteger var9 = var5.add(var8.getAffineXCoord().toBigInteger()).mod(var3);
            return var9.equals(var1);
          }
        }
      } else {
        return false;
      }
    } else {
      return false;
    }
  }

  private byte[] digestDoFinal() {
    byte[] var1 = new byte[this.digest.getDigestSize()];
    this.digest.doFinal(var1, 0);
    this.reset();
    return var1;
  }

  private byte[] getZ(byte[] var1) {
    this.digest.reset();
    this.addUserID(this.digest, var1);
    this.addFieldElement(this.digest, this.ecParams.getCurve().getA());
    this.addFieldElement(this.digest, this.ecParams.getCurve().getB());
    this.addFieldElement(this.digest, this.ecParams.getG().getAffineXCoord());
    this.addFieldElement(this.digest, this.ecParams.getG().getAffineYCoord());
    this.addFieldElement(this.digest, this.pubPoint.getAffineXCoord());
    this.addFieldElement(this.digest, this.pubPoint.getAffineYCoord());
    byte[] var2 = new byte[this.digest.getDigestSize()];
    this.digest.doFinal(var2, 0);
    return var2;
  }

  private void addUserID(Digest var1, byte[] var2) {
    int var3 = var2.length * 8;
    var1.update((byte) (var3 >> 8 & 255));
    var1.update((byte) (var3 & 255));
    var1.update(var2, 0, var2.length);
  }

  private void addFieldElement(Digest var1, ECFieldElement var2) {
    byte[] var3 = var2.getEncoded();
    var1.update(var3, 0, var3.length);
  }

  protected ECMultiplier createBasePointMultiplier() {
    return new FixedPointCombMultiplier();
  }

  protected BigInteger calculateE(BigInteger var1, byte[] var2) {
    return new BigInteger(1, var2);
  }
}
